package com.twetec.cms.adapter.pc.backend.controller.ucenter;

import com.twetec.cms.adapter.pc.backend.response.R;
import com.twetec.cms.common.constant.ConstantsEnum;
import com.twetec.cms.common.constant.RedisConst;
import com.twetec.cms.common.util.cache.RedisCache;
import com.twetec.cms.common.util.cache.SSOToken;
import com.twetec.cms.common.util.jwt.JWTUtil;
import com.twetec.cms.model.operter.CmsOperter;
import com.twetec.cms.model.vo.system.PermissionVO;
import com.twetec.cms.model.vo.system.RolePermissionVO;
import com.twetec.cms.model.vo.system.RoleUserVO;
import com.twetec.cms.model.vo.system.RoleVO;
import com.twetec.cms.model.vo.ucenter.UserVO;
import com.twetec.cms.service.system.PermissionService;
import com.twetec.cms.service.system.RolePermissionService;
import com.twetec.cms.service.system.RoleService;
import com.twetec.cms.service.system.RoleUserService;
import com.twetec.cms.service.ucenter.UserService;
import com.xxg.base.module.Operater;
import com.zgh.rbac.module.Menu;
import com.zgh.rbac.module.Role;
import com.zgh.rbac.service.DataPowerService;
import com.zgh.rbac.service.RbacProxy;
import com.zgh.usercenter.module.Organization;
import com.zgh.usercenter.module.User;
import com.zgh.usercenter.service.UserCenterProxy;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Api(tags = "用户鉴权模块")
@CrossOrigin
@RestController
@RequestMapping("/ucenter/auth")
public class AuthController {

    private static final Logger logger = LoggerFactory.getLogger(AuthController.class);

    // TODO:菜单前缀
    private static final String ROUTE_PREFIX = "cms/";

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private UserCenterProxy userCenterProxy;

    @Autowired
    private RbacProxy rbacProxy;

    @Autowired
    private DataPowerService dataPowerService;

    @Autowired
    private UserService userService;

    @Autowired
    private PermissionService permissionService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private RoleUserService roleUserService;

    @Autowired
    private RolePermissionService rolePermissionService;

    /**
     * 用户登录（ssost->loginKey->ssoToken(issure)->user）
     */
    @ApiOperation(
            value = "用户登录",
            notes = "利用sso_token换取jwt,返回给客户端"
    )
    @PostMapping("/user-login")
    public R userLogin(
            @ApiParam(value = "ssost", example = "单点登录的token") @RequestParam(value = "ssost", required = false) String ssost
    ) throws ParseException {

        // 校验ssost
        if (StringUtils.isBlank(ssost)) { return R.failureRequestParam().msg("ssost必填"); }

        // 如果ssost不为空，则用ssost去工会平台换取loginKey
        String loginKey = redisCache.getString(ssost);
        // loginKey拿过一次后，ssost作废
        redisCache.delete(ssost);

        // 如果loginKey为空，则需要用户重新登录
        if(StringUtils.isBlank(loginKey)) return R.failureUserAuth().msg("用户鉴权失败: loginKey，请重试。");

        // 用loginKey从redis中换取用户身份, SSOToken为不实现Serioizel接口
        SSOToken ssoToken = redisCache.getObj(loginKey, SSOToken.class);

        // 如果ssoToken为空，则需要用户重新登录
        if(ssoToken == null || StringUtils.isBlank(ssoToken.getIssuer())) return R.failureUserAuth().msg("用户鉴权失败: ssoToken，请重试。");

        // 用ssoToken获取用户信息，并存入操作者信息对象中
        Operater operater = new Operater();
        operater.setIp(ssoToken.getIp());
        operater.setBusinessCode(ssoToken.getId());
        operater.setUserId(Long.valueOf(ssoToken.getIssuer()));
        // 从redis中获取用户信息(都是从redis中获取的)
        User user = userCenterProxy.getUser(operater.getUserId());

        // 将获取到的用户信息存入operater
        operater.setUserId(user.getId());
        operater.setMobile(user.getMobile());
        operater.setEmail(user.getEmail());
        operater.setFullName(user.getFullName());
        operater.setSex(user.getSex());
        operater.setCertificationLevel(user.getCertificationLevel());
        operater.setIdcardType(user.getIdcardType());
        operater.setIdcardCode(user.getIdcardCode());
        operater.setUserType(user.getUserType());

        // 缓存用户信息，方法中是完善operater操作者的信息
        userCenterProxy.setOperater(operater);

        //用户当前部门ID默认为主部门ID
        operater.setOrgType("business");
        //业务系统，orgId与bigOrgId是一样的
        operater.setOrgId(operater.getMasterOrganizationId());
        operater.setBigOrgId(operater.getMasterOrganizationId());

        // 获得用户的组织信息
        Organization oao = userCenterProxy.getOrganization(operater.getOrgId());
        if(oao != null && oao.getId() != null && oao.getId() > 0){
            operater.setUserDataCode(oao.getOrganizationCode());

            operater.setOrgName(oao.getOrganizationName());
            operater.setBigOrgName(oao.getOrganizationName());
        }

//        // 1.保存用户信息到Oracle数据库，
        boolean saveUserInfo = saveUserInfo(user, oao.getOrganizationCode());
        if (!saveUserInfo) { return R.failureUserAuth().msg("用户登录失败: 请重试。"); }

        // 工会用户id
        Long unionMemberId = user.getId();
        // 获取资讯发布系统用户信息
        UserVO userVO = userService.getByUnionMemberId(String.valueOf(unionMemberId));
        if (userVO == null) { return R.failureUserAuth().msg("用户鉴权失败: 请重试。"); }

        // 2.保存资讯发布系统所有权限到数据库
        Long userId = userVO.getId();
        String telephone = userVO.getTelephone();

        // TODO:: 权限信息待处理
//        // 获取权限
//        List<Menu> menus = rbacProxy.listMenu(unionMemberId, "1", "1");
//        if (menus.isEmpty()) { return R.failureUserAuth().msg("用户鉴权失败: 请重试。"); }
//        // 筛选出资讯发布的权限
//        List<Menu> menuList = getMenuList(menus);
//        // 保存权限到数据库
//        boolean savePermission = savePermission(menuList);
//        if (!savePermission) { return R.failureUserAuth().msg("用户鉴权失败: 请重试。"); }

//        // 3.批量更新权限pid
//        boolean batchUpdatePid = permissionService.batchUpdatePid();

//        // 4.保存角色,角色和用户,角色和权限到数据库
//        boolean saveRoleAndRoleUserAndRolePermission = saveRoleAndRoleUserAndRolePermission(unionMemberId, userId);
//        if (!saveRoleAndRoleUserAndRolePermission) { return R.failureUserAuth().msg("用户鉴权失败: 请重试。"); }

        // 5.把用户信息和权限存入redis
        // 5.1存入用户信息
        // 用户的数据域
        Map<String, String> userInfoMap = new HashMap<>();
        String orgCode = oao.getOrganizationCode();
        userInfoMap.put("userId", String.valueOf(userId));
        if (orgCode == null) {
            userInfoMap.put("orgCode", "");
        } else {
            userInfoMap.put("orgCode", orgCode);
        }

        // 缓存操作者数据
        redisCache.delete(RedisConst.REDISKEY_OPERATER_INFO + userId);
        redisCache.setObj(RedisConst.REDISKEY_OPERATER_INFO + userId, operater);

        // 5.2存入数据域
        Map<String, String> userOrgInfoMap = new HashMap<>();
        // 获取数据权限
        Map<String, Object> dataPowerMap = dataPowerService.setPower(null, null, operater);

        if (dataPowerMap != null) {
            // 权限用户id
            String powerUserIds = String.valueOf(dataPowerMap.get("powerUserIds"));
            // 组织权限代码
            String powerOrgCodes = String.valueOf(dataPowerMap.get("powerOrganizationCodes"));
            // 以工会ids循环匹配资讯发布用户id
            String userIds = userService.getUserIdsByUnionMemberIds(powerUserIds);
            if (userIds == null) {
                userOrgInfoMap.put("userIds", "");
            } else {
                userOrgInfoMap.put("userIds", userIds);
            }
            if (powerOrgCodes == null) {
                userOrgInfoMap.put("powerOrgCodes", "");
            } else {
                userOrgInfoMap.put("powerOrgCodes", powerOrgCodes);
            }
            redisCache.delete(RedisConst.REDISKEY_USER_ORG_INFO + userId);
            redisCache.setMap(RedisConst.REDISKEY_USER_ORG_INFO + userId, userOrgInfoMap);
        }

        // TODO::权限信息待处理
//        // 5.3存入权限
//        List<PermissionVO> permissionVOList = permissionService.getPermissionListByUserId(userId);
//        redisCache.delete(RedisConst.REDISKEY_PERMISSION_LIST + userId);
//        redisCache.setList(RedisConst.REDISKEY_PERMISSION_LIST + userId, permissionVOList);

        // 登录成功，并获取到用户信息后，返回jwt给客户端(教育平台的userid, 教育平台的签发者，教育平台的用户名)
        String jwt = JWTUtil.generateToken(String.valueOf(userId), "XM-UNION-CMS", telephone);

        // 将用户权限信息存入redis
        userService.addPermissionMenuListInRedis(userId);

        Map<String, String> resp = new HashMap<>();
        resp.put("jwt", jwt);

        return R.success().data(resp);
    }

    /**
     * 用户权限查询
     */
    @ApiOperation(
            value = "用户权限查询",
            notes = "根据jwt,返回用户的功能权限列表"
    )
    @GetMapping("/get-user-auth-list")
    public R<List<PermissionVO>> getUserAuthList(
            @ApiParam(value = "userId", example = "3343434") @RequestParam(value = "userId", required = false) Long userId
    ) {
        // 1.判断redis是否有权限
        List<PermissionVO> list = redisCache.getList(RedisConst.REDISKEY_PERMISSION_LIST + userId);

        // 返回数据
        List<PermissionVO> permissionVOList = new ArrayList<>();

        // 2.存在, 就从redis获取权限
        if (!list.isEmpty()) {
            permissionVOList = list;
        } else {
            // 3.不存在, 从数据库获取
            permissionVOList = permissionService.getPermissionListByUserId(userId);
        }

        System.out.println(  "用户权限接口permissionVOList"+permissionVOList);
        return R.success().data(permissionVOList);
    }

    @ApiOperation(
            value = "用户站点权限查询",
            notes = "根据用户id,返回用户的站点权限"
    )
    @GetMapping("/get-user-permission-menu-list")
    public R<List<Object>> getUserPermissionMenuList(@RequestAttribute("userId") Long userId) {
        List<Object> permissionMenuList = userService.getPermissionMenuListFromRedis(userId);
        return R.success().data(permissionMenuList);
    }



//
//    /**
//     * 用户信息查询
//     */
    @ApiOperation(value = "用户信息查询", notes = "根据jwt,返回用户的信息")
    @GetMapping("/get-user-info")
    public R<UserVO> getUserInfo(
            @ApiParam(value = "userId", example = "3343434") @RequestParam(value = "userId", required = false) Long userId
    ) {

        // 获取用户信息
        UserVO userVO = userService.getByUserId(userId);

        if (null == userVO){
            return R.failure().msg("未找到该用户");
        }
        CmsOperter cmsOperter = new CmsOperter();
        cmsOperter.setId(userId);
        // cmsOperter.setDataOrg(userVO.getDataOrg());
        cmsOperter.setName(userVO.getName());
//        cmsOperter.setUnions(userVO.getUnions());
//        cmsOperter.setUnit(userVO.getUnit());
        // 判断redis中是否存在用户信息
        redisCache.delete(RedisConst.REDISKEY_OPERATER_INFO + userId);
        boolean b = redisCache.setObj(RedisConst.REDISKEY_OPERATER_INFO + userId, cmsOperter);
        if (!b){
            logger.info("保存用户信息失败");
        }
        return R.success().data(userVO);
    }


    @ApiOperation(
            value = "保存用户信息到redis中",
            notes = "保存用户信息到redis中"
    )
    @PostMapping("/save-user-redis")
    public R saveUserRedis(@RequestAttribute("userId") Long userId) {
        userService.addPermissionMenuListInRedis(userId);
        return R.success();
    }

    /**
     * 新增 / 更新用户表
     */
    private boolean saveUserInfo(User user, String dataOrg) throws ParseException {

        // 整理数据格式
        Long unionMemberId = user.getId();
        String fullName = user.getFullName();
        String avatar = "";
        String idcardType = user.getIdcardType();
        String idcardCode = user.getIdcardCode();
        String mobile = user.getMobile();
        String status = ConstantsEnum.Enable.ON.getValue();
        String birthday = user.getBirthdayShow();
        String sex = user.getSex();
        String companyName = user.getCompanyName();
        String labourUnionName = user.getLabourUnionName();

        // 时间整理
        SimpleDateFormat formatter = new SimpleDateFormat( "yyyy-MM-dd");
        Date newBirthday = null;
        if (birthday != null) {
            newBirthday = formatter.parse(birthday);
        }

        // 男性
        if (sex.equals("1")) {
            sex = ConstantsEnum.Gender.MALE.getValue();
        } else if (sex.equals("2")) {
            // 女性
            sex = ConstantsEnum.Gender.FEMALE.getValue();
        } else {
            // 其他
            sex = ConstantsEnum.Gender.MALE.getValue();
        }

        // 身份证
        if ("1".equals(idcardType)) {
            idcardType = ConstantsEnum.CredentialType.ID_CARD.getValue();
        }
        // 回乡证
        else if ("2".equals(idcardType)) {
            idcardType = ConstantsEnum.CredentialType.GO_HOME_CARD.getValue();
        }
        // 台胞证
        else if ("3".equals(idcardType)) {
            idcardType = ConstantsEnum.CredentialType.TAIWAN_COMPATRIOTS_CARD.getValue();
        }
        // 护照
        else if ("4".equals(idcardType)) {
            idcardType = ConstantsEnum.CredentialType.PASSPORT_CARD.getValue();
        }

        // 1. 查询是否存在该用户
        UserVO userVO = userService.getByUnionMemberId(String.valueOf(unionMemberId));
        boolean result = true;
        // 1.1 存在,更新
        if (userVO != null) {
            result = userService.updateById(String.valueOf(unionMemberId), fullName, avatar, idcardType, idcardCode, mobile, status, newBirthday, sex, companyName, labourUnionName, dataOrg);
        } else {
            // 1.2 不存在,新增
            userService.create(String.valueOf(unionMemberId), fullName, avatar, idcardType, idcardCode, mobile, status, newBirthday, sex, companyName, labourUnionName,  dataOrg);
        }

        if (!result) {
            return false;
        }

        return result;
    }

    /**
     * 新增 / 更新在线教育权限表
     */
    private boolean savePermission(List<Menu> menuList) {

        List<PermissionVO> permissionVOList = new ArrayList<>();

        // 循环保存权限
        for (Menu menu : menuList) {
            // 整理权限
            Long unionPermissionId = menu.getId();
            long unionPid = menu.getParentId();
            String name = menu.getMenuName();
            String slug = menu.getUrl();
            String type = menu.getIfMenu();
            String httpPath = menu.getUrl();

            // 按钮
            if (type.equals("0")) {
                type = ConstantsEnum.PermissionType.BUTTON.getValue();
            } else if (type.equals("1")) {
                // 菜单
                type = ConstantsEnum.PermissionType.MENU.getValue();
            }
            PermissionVO permissionVO = new PermissionVO();
            permissionVO.setUnionPid(unionPid);
            permissionVO.setHttpPath(httpPath);
            permissionVO.setType(type);
            permissionVO.setSlug(slug);
            permissionVO.setUnionPermissionId(unionPermissionId);
            permissionVO.setName(name);

            permissionVOList.add(permissionVO);
        }
        return permissionService.createAndUpdate(permissionVOList);
    }

    /**
     * 新增 / 更新角色表
     */
    private boolean saveRole(Role role) {

        // 整理权限
        Long unionRoleId = role.getId();
        String roleName = role.getRoleName();

        // 1.判断角色数据是否存在
        RoleVO roleVO = roleService.getByUnionRoleId(unionRoleId);

        boolean result = true;
        // 1.1 存在, 更新
        if (roleVO != null) {
            result =  roleService.updateByUnionRoleId(unionRoleId, roleName);
        } else {
            // 1.2 不存在,新增
            result =  roleService.create(unionRoleId, roleName);
        }

        return result;
    }

////
//    /**
//     * 根据工会用户id获取用户的角色列表
//     */
//    private List<Role> roleList(Long unionUserId) {
//
//        // 1.获取所有角色
//        List<Role> roles = rbacProxy.listRole();
////        System.out.println(roles);
//
//        for(Role role : roles){
//            System.out.println("role.getRoleAndOrganizations用户包含的组织"+role.getRoleAndOrganizations());
//            System.out.println("role.getOrganizationAndRoles角色的数据权限-组织"+role.getOrganizationAndRoles());
//        }
//
//        // 存储用户的角色列表
//        List<Role> roleList = new ArrayList<>();
//
//        // 2.遍历所有角色,获取用户的角色列表
//        for (Role role : roles) {
////            // 用户ids
////            List<Long> userIds = role.getUserIds();
////            // 判断用户ids存在用户id, 存入到用户的角色列表
////            if (userIds.contains(unionUserId))
////                roleList.add(role);
//
//        }
//
//        return roleList;
//    }


    /**
     * 保存角色表,角色和用户表,角色和权限表
     */
    private boolean saveRoleAndRoleUserAndRolePermission(Long unionUserId, Long userId) {

        // 1.获取用户的角色列表
        List<Role> roleList = rbacProxy.getRoleByUserId(unionUserId, null);
        // 用户和角色列表
        List<RoleUserVO> roleUserVOList = new ArrayList<>();

        List<Long> roleIdList = new ArrayList<>();
        // 遍历角色列表
        for (Role role : roleList) {
            // 2.存入到角色表
            boolean saveRole = saveRole(role);
            if (!saveRole) { continue; }
            // 这里是去获取角色id
            // 工会角色id
            Long unionRoleId = role.getId();
            // 获取角色信息
            RoleVO roleVO = roleService.getByUnionRoleId(unionRoleId);
            if (roleVO == null) { continue; }
            // 在线教育角色id
            Long roleId = roleVO.getId();
            roleIdList.add(roleId);
            // 开始整理与用户和角色数据
            RoleUserVO roleUserVO = new RoleUserVO();
            roleUserVO.setUserId(userId);
            roleUserVO.setRoleId(roleId);
            roleUserVOList.add(roleUserVO);
            // 开始整理角色和权限数据
            List<RolePermissionVO> rolePermissionVOList = new ArrayList<>();
            // 获取角色对应的工会权限id
            List<Long> menuIds = role.getMenuIds();
            if(null == menuIds || menuIds.isEmpty()){ continue; }
            // 根据工会权限id获取在线教育权限列表
            List<PermissionVO> permissionVOList = permissionService.getPermissionList(menuIds);
            if (null == permissionVOList || permissionVOList.isEmpty()) { continue; }
//            map.put(roleId, permissionList);
//            // 循环权限
            for (PermissionVO permissionVO : permissionVOList) {
                RolePermissionVO rolePermissionVO = new RolePermissionVO();
                // 权限id
                rolePermissionVO.setPermissionId(permissionVO.getId());
                rolePermissionVO.setRoleId(roleId);
                rolePermissionVOList.add(rolePermissionVO);
            }
            boolean saveRolePermission = rolePermissionService.create(rolePermissionVOList, roleId);
            if (!saveRolePermission) { return false; }
        }
        // 4.存入到用户和角色关联表
        // 3.存入到角色和权限关联表

        boolean saveRoleUser = roleUserService.create(roleUserVOList, userId);
        if (!saveRoleUser) { return false; }
        return true;
    }



    private List<Menu> getMenuList(List<Menu> menuList){
        List<Menu> permissionList = new ArrayList<>();
        // 循环整理数据
        for (Menu menu : menuList) {
            // 获取路由
            String url = menu.getUrl();
            if (url == null) { continue; }

            // 匹配前缀
            int isHaveRoutePrefix = url.indexOf(ROUTE_PREFIX);
            if (isHaveRoutePrefix == -1) { continue; }

            // 替换前缀
            String newUrl = url.replaceAll(ROUTE_PREFIX, "/");
            menu.setUrl(newUrl);

            permissionList.add(menu);
        }
        return permissionList;
    }
}

